/**
 * 
 */
package com.cipe.cmrs.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.cipe.cmrs.bean.CipeprojectBean;
import com.cipe.cmrs.exception.CipeprojectException;
import com.cipe.cmrs.exception.QueryException;
import com.cipe.cmrs.model.Audits;
import com.cipe.cmrs.model.Cipeproject;
import com.cipe.cmrs.model.Cipeprojectmodification;
import com.cipe.cmrs.model.Cipeprojectstatus;
import com.cipe.cmrs.model.Cipeprojecttype;
import com.cipe.cmrs.model.Country;
import com.cipe.cmrs.model.Keyword;
import com.cipe.cmrs.model.Modificationtype;
import com.cipe.cmrs.model.Organizationtype;
import com.cipe.cmrs.model.Region;
import com.cipe.cmrs.model.User;
import com.cipe.cmrs.util.Constants;
import com.cipe.cmrs.util.DateUtil;
import com.cipe.cmrs.util.DateUtil2;
import com.cipe.cmrs.util.NumberUtil;
import com.cipe.cmrs.util.Util;

/**
 * @author Incepio
 */
@Service
@Transactional
public class CipeprojectService extends BaseService<Cipeproject> {

	@Autowired
	private UserService userService;
	@Autowired
	private CipeprojecttypeService cipeprojecttypeService;
	@Autowired
	private CipeprojectstatusService cipeprojectstatusService;
	@Autowired
	private ConversionService conversionService;
	@Autowired
	private AuditsService auditsService;
	@Autowired
	private ModificationTypeService modificationTypeService;
	@Autowired
	private KeywordService keywordService;

	/**
	 * @param id
	 */
	private Cipeproject findByCostCenterNumber(Integer id) {
		Cipeproject cipeproject = null;
		try {
			String query = "from Cipeproject where " + Util.createFirstQueryClause("costCenterNumber", id);
			cipeproject = this.dao.getSingleResult(query);
		} catch (Exception exp) {
			logger.error(exp.getMessage(), exp);
		}
		return cipeproject;
	}

	@Transactional(propagation = Propagation.SUPPORTS, readOnly = false)
	public Long countByProjectID(String id) {
		String query = "select count(o) from Cipeproject o where " + Util.createFirstQueryClause("projectID", id);
		List results = this.dao.getResultList(query);

		return (results != null ? (Long) results.get(0) : 0L);
	}

	/**
	 * This method will call database procedure with native query and get the
	 * result\
	 * 
	 * @author Krushna
	 * @param procedureName
	 * @return
	 */
	public List<Cipeproject> findCipeproject(String procedureName) {
		return this.dao.getResultListWithNativeQuery(procedureName, Cipeproject.class, null);
	}

	/**
	 * Return the list of project with paymentrequestid
	 * 
	 * @param id
	 * @return
	 */
	public List<Cipeproject> findCipeproject(int id, String procedureName) {
		return this.dao.getResultListWithNativeQuery(procedureName, Cipeproject.class, id);
	}

	public List<Cipeproject> findCipeproject(Cipeproject cipeproject) {
		/*
		 * Object[] params = { cipeproject.getProjectID(),
		 * cipeproject.getAcronym(), cipeproject.getPartner() != null ?
		 * cipeproject.getPartner() : null, cipeproject.getProjectTitle(),
		 * cipeproject.getCipeprojecttype() != null ?
		 * cipeproject.getCipeprojecttype() : null,
		 * cipeproject.getProgramOfficer() != null ?
		 * cipeproject.getProgramOfficer() : null,
		 * cipeproject.getProgramAssistant() != null ?
		 * cipeproject.getProgramAssistant() : null, cipeproject.getRegion() !=
		 * null ? cipeproject.getRegion() : null, cipeproject.getCountry() !=
		 * null ? cipeproject.getCountry() : null,
		 * cipeproject.getCipeprojectstatus() != null ?
		 * cipeproject.getCipeprojectstatus() : null,
		 * cipeproject.getFiscalYear(),
		 * cipeproject.getInitialProjectStartDate(),
		 * cipeproject.getFinalProjectStartDate(),
		 * cipeproject.getInitialProjectEndDate(),
		 * cipeproject.getFinalProjectEndDate(),
		 * cipeproject.getInitialManagementFunds(),
		 * cipeproject.getFinalManagementFunds() };
		 */
		List<Cipeproject> cipeprojectList = new ArrayList<Cipeproject>();
		try {
			// Cipeprojecttype type =
			// this.cipeprojecttypeService.findByDisplayName(Constants.PartnerGrant);
			String query = "from Cipeproject where"
					+ Util.createlikeFirstQueryClause("projectID", cipeproject.getProjectID()) // +
																								// Util.createNotEqualQueryClause(type)
					+ Util.createlikeQueryClause("acronym", cipeproject.getAcronym()) + Util.createQueryClause(cipeproject.getPartner())
					+ Util.createlikeQueryClause("projectTitle", cipeproject.getProjectTitle()) + Util.createQueryClause(cipeproject.getCipeprojecttype())
					+ Util.createQueryClause(cipeproject.getProgramOfficer(), "programOfficer") + Util.createQueryClause(cipeproject.getProgramAssistant(), "programAssistant")
					+ Util.createQueryClause(cipeproject.getRegion()) + Util.createQueryClause(cipeproject.getCountry())
					+ Util.createQueryClause(cipeproject.getCipeprojectstatus()) + Util.createQueryClause("fiscalYear", cipeproject.getFiscalYear())
					+ Util.createRangeQueryClause("projectStartDate", cipeproject.getInitialProjectStartDate(), cipeproject.getFinalProjectStartDate())
					+ Util.createRangeQueryClause("projectEndDate", cipeproject.getInitialProjectEndDate(), cipeproject.getFinalProjectEndDate())
					+ Util.createRangeQueryClause("managementFunds", cipeproject.getInitialManagementFunds(), cipeproject.getFinalManagementFunds())
					+ Util.createOrderByDesc("projectenddate");
			cipeprojectList = this.dao.getResultList(query);
			// cipeprojectList = dao.getNamedQueryResultList("findCipeproject",
			// params);
		} catch (Exception exp) {
			logger.error(exp.getMessage(), exp);
		}
		return cipeprojectList;
	}

	public List<Cipeproject> findKnowledgeManagement(Cipeproject cipeproject) {
		List<Cipeproject> cipeprojectList = new ArrayList<Cipeproject>();
		try {
			// Cipeprojecttype type =
			// this.cipeprojecttypeService.findByDisplayName(Constants.PartnerGrant);
			// String queryKeyword =
			// "from p Cipeproject p LEFT JOIN p.projectkeywords keywords where ";
			String query = "from Cipeproject p where";
			if (cipeproject.getKeywordId1() != null || cipeproject.getKeywordId2() != null || cipeproject.getKeywordId3() != null) {
				query = "from Cipeproject p LEFT JOIN p.projectkeywords projectKeyword where";
			}
			query = query + Util.createlikeFirstQueryClause("p.projectID", cipeproject.getProjectID()) + Util.createQueryClause("p.acronym", cipeproject.getAcronym())
					+ Util.createQueryClause(cipeproject.getPartner()) + Util.createQueryClause("p.projectTitle", cipeproject.getProjectTitle())
					+ Util.createQueryClause(cipeproject.getCipeprojecttype()) + Util.createQueryClause(cipeproject.getProgramOfficer(), "p.programOfficer")
					+ Util.createQueryClause(cipeproject.getProgramAssistant(), "p.programAssistant") + Util.createQueryClause(cipeproject.getRegion())
					+ Util.createQueryClause(cipeproject.getCountry()) + Util.createGTQueryClause("p.themebusassocdev", cipeproject.getThemebusassocdev())
					+ Util.createQueryClause("p.themelegalregreform", cipeproject.getThemelegalregreform())
					+ Util.createGTQueryClause("p.themewomenyouth", cipeproject.getThemewomenyouth())
					+ Util.createQueryClause("p.themeaccesstoinfo", cipeproject.getThemeaccesstoinfo())
					+ Util.createGTQueryClause("p.themecorruption", cipeproject.getThemecorruption())
					+ Util.createQueryClause("p.themecorporategovernance", cipeproject.getThemecorporategovernance())
					+ Util.createGTQueryClause("p.themedemocraticgovernance", cipeproject.getThemedemocraticgovernance())
					+ Util.createQueryClause(cipeproject.getCipeprojectstatus()) + Util.createQueryClause("p.fiscalYear", cipeproject.getFiscalYear())
					+ Util.createRangeQueryClause("p.projectStartDate", cipeproject.getInitialProjectStartDate(), cipeproject.getFinalProjectStartDate());
			// + Util.createRangeQueryClause("projectEndDate",
			// cipeproject.getInitialProjectEndDate(),
			// cipeproject.getFinalProjectEndDate())
			if (cipeproject.getKeywordId1() != null) {
				query = query + " projectKeyword.keyword.id " + cipeproject.getCondition1() + " " + cipeproject.getKeywordId1();
			}
			if (cipeproject.getKeywordId2() != null) {
				query = query + " projectKeyword.keyword.id " + cipeproject.getCondition2() + " " + cipeproject.getKeywordId2();
			}
			if (cipeproject.getKeywordId3() != null) {
				query = query + " projectKeyword.keyword.id " + cipeproject.getCondition3() + " " + cipeproject.getKeywordId3();
			}
			query = query + Util.createRangeQueryClause("p.managementFunds", cipeproject.getInitialManagementFunds(), cipeproject.getFinalManagementFunds())
					+ Util.createOrderByAsc("p.projectID" + ", p.partner.partnerName ");
			cipeprojectList = this.dao.getResultList(query);
		} catch (Exception exp) {
			logger.error(exp.getMessage(), exp);
		}
		return cipeprojectList;
	}

	public List<Cipeproject> findPartnergrant(Cipeproject cipeproject) {
		List<Cipeproject> cipeprojectList = new ArrayList<Cipeproject>();
		try {
			Cipeprojecttype type = this.cipeprojecttypeService.findByDisplayName(Constants.PartnerGrant);
			String query = "from Cipeproject where" + Util.createlikeFirstQueryClause("projectID", cipeproject.getProjectID()) + Util.createQueryClause(type)
					+ Util.createlikeQueryClause("acronym", cipeproject.getAcronym()) + Util.createQueryClause(cipeproject.getPartner())
					+ Util.createlikeQueryClause("projectTitle", cipeproject.getProjectTitle()) + Util.createQueryClause(cipeproject.getProgramOfficer(), "programOfficer")
					+ Util.createQueryClause(cipeproject.getProgramAssistant(), "programAssistant") + Util.createQueryClause(cipeproject.getRegion())
					+ Util.createQueryClause(cipeproject.getCountry()) + Util.createQueryClause(cipeproject.getCipeprojectstatus())
					+ Util.createQueryClause("fiscalYear", cipeproject.getFiscalYear())
					+ Util.createRangeQueryClause("projectStartDate", cipeproject.getInitialProjectStartDate(), cipeproject.getFinalProjectStartDate())
					+ Util.createRangeQueryClause("projectEndDate", cipeproject.getInitialProjectEndDate(), cipeproject.getFinalProjectEndDate())
					+ Util.createRangeQueryClause("managementFunds", cipeproject.getInitialManagementFunds(), cipeproject.getFinalManagementFunds())
					+ Util.createOrderByDesc("projectenddate");
			cipeprojectList = this.dao.getResultList(query);
		} catch (Exception exp) {
			logger.error(exp.getMessage(), exp);
		}
		return cipeprojectList;
	}

	@Transactional(readOnly = true)
	@Deprecated
	/**
	 * 
	 * @param columns
	 * @return
	 * @deprecated replaced by getAllActiveCipeProjects
	 */
	public List<CipeprojectBean> getAllCipeProjects(List<String> columns) {
		List<CipeprojectBean> results = new ArrayList<CipeprojectBean>();
		StringBuilder queryString = new StringBuilder("SELECT ");
		if (columns != null && columns.size() > 0) {
			int i = 0;
			for (; i < columns.size() - 1; i++) {
				queryString.append("obj." + columns.get(i) + ", ");
			}
			queryString.append("obj." + columns.get(i));
		} else {
			queryString.append("obj");
		}
		queryString.append(" FROM ");
		queryString.append(Cipeproject.class.getName());
		queryString.append(" obj ");
		queryString.append(" ORDER BY obj.id ASC ");
		try {
			List<Cipeproject> projects = dao.getResultList(queryString.toString(), Cipeproject.class, columns.toArray(new String[0]), null);
			if (projects != null) {
				for (Cipeproject project : projects) {
					results.add(conversionService.convert(project, CipeprojectBean.class));
				}
			}
		} catch (QueryException e) {
			// XXX: User should be notified by this.
			logger.error("Exception encountered while fetching Cipeproject from db.", e);
		}
		return results;
	}

	/**
	 * Get all active projects which satisfies any of following conditions<br/>
	 * <ul>
	 * <li>status = 'Active'</li>
	 * <li>status = 'Over' and projectType != 'Partner' and projectEndDate !=
	 * null and projectEndDate <= 30 from current date</li>
	 * <li>override = TRUE (BLOG476)</li>
	 * <li>statusoverride = TRUE (BLOG476)</li>
	 * </ul>
	 * 
	 * @param columns
	 * @return
	 */
	@Transactional(readOnly = true)
	public List<CipeprojectBean> getAllActiveCipeProjects(List<String> columns) {
		List<CipeprojectBean> results = new ArrayList<CipeprojectBean>();
		List<Object> parameters = new ArrayList<Object>();
		StringBuilder queryString = new StringBuilder("SELECT ");
		if (columns != null && columns.size() > 0) {
			int i = 0;
			for (; i < columns.size() - 1; i++) {
				queryString.append("obj." + columns.get(i) + ", ");
			}
			queryString.append("obj." + columns.get(i));
		} else {
			queryString.append("obj");
		}
		queryString.append(" FROM ");
		queryString.append(Cipeproject.class.getName());
		queryString.append(" obj ");
		queryString.append(" where ");
		queryString.append("UPPER(cipeprojectstatus.displayName) = ?1");
		queryString.append(" OR ");
		queryString.append("(");
		queryString.append(" UPPER(cipeprojectstatus.displayName) = ?2");
		queryString.append(" AND ");
		queryString.append(" UPPER(cipeprojecttype.displayName) != ?3");
		queryString.append(" AND ");
		queryString.append(" projectEndDate IS NOT NULL");
		queryString.append(" AND ");
		queryString.append(" projectEndDate BETWEEN ?4 AND ?5");
		queryString.append(")");
		queryString.append(" OR ");
		queryString.append(" override = ?6 ");
		queryString.append(" OR ");
		queryString.append(" statusoverride = ?7 ");

		parameters.add(getText("statusname.status.project.active").toUpperCase());
		parameters.add(getText("statusname.status.project.over").toUpperCase());
		parameters.add(getText("projecttype.partner").toUpperCase());

		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DAY_OF_YEAR, -30);
		Date start = DateUtil2.INSTANCE.getSodDate(cal.getTime());
		Date end = DateUtil2.INSTANCE.getEodDate(new Date());

		parameters.add(start);
		parameters.add(end);
		parameters.add(Boolean.TRUE);
		parameters.add(Boolean.TRUE);

		queryString.append(" ORDER BY obj.projectID, obj.cipeprojecttype.displayName ASC ");
		try {
			List<Cipeproject> projects = dao.getResultList(queryString.toString(), Cipeproject.class, columns.toArray(new String[0]), parameters.toArray(new Object[0]));
			if (projects != null) {
				for (Cipeproject project : projects) {
					results.add(conversionService.convert(project, CipeprojectBean.class));
				}
			}
		} catch (QueryException e) {
			// XXX: User should be notified by this.
			logger.error("Exception encountered while fetching Cipeproject from db.", e);
		}
		return results;
	}

	/**
	 * @param id
	 * @return
	 */
	@Transactional(readOnly = true)
	public CipeprojectBean getCipeproject(Integer id) {
		Assert.notNull(id);
		CipeprojectBean result = null;
		Cipeproject dbCipeproject = findById(id);
		if (dbCipeproject != null) {
			result = new CipeprojectBean();
			result.setNedIdentifier(dbCipeproject.getNedIdentifier());
			result.setDonorName(dbCipeproject.getDonoraward().getDonor().getDonorName());
			result.setAcronym(dbCipeproject.getAcronym());
			result.setTitle(dbCipeproject.getProjectTitle());
			result.setCostCenterNumber(dbCipeproject.getCostCenterNumber());
			Map<String, String> donoraward = null;
			if (null != dbCipeproject.getDonoraward()) {
				donoraward = new HashMap<String, String>();
				donoraward.put(dbCipeproject.getDonoraward().getId().toString(), dbCipeproject.getDonoraward().getDonorAwardNumber());
			}
			result.setDonoraward(donoraward);
			String pattern = DateUtil2.DEFAULT_PATTERN;
			result.setFormattedStartDate(DateUtil2.INSTANCE.formatDate(pattern, dbCipeproject.getProjectStartDate()));
			result.setFormattedEndDate(DateUtil2.INSTANCE.formatDate(pattern, dbCipeproject.getProjectEndDate()));
		}
		return result;
	}

	/**
	 * @return
	 */
	public List<Cipeproject> getPartnerParentList() {
		List<Cipeproject> cipeprojectList = new ArrayList<Cipeproject>();
		try {
			Cipeprojecttype type = this.cipeprojecttypeService.findByDisplayName(Constants.PartnerGrant);
			Cipeprojectstatus status = this.cipeprojectstatusService.findByDisplayName(Constants.Active);
			String query = "from Cipeproject where " + Util.createFirstNotEqualQueryClause("cipeprojecttype", type.getId())
					+ Util.createQueryClause("cipeprojectstatus", status.getId()) + " order by donoraward.donorAwardNumber asc";
			cipeprojectList = this.dao.getResultList(query);
		} catch (Exception exp) {
			logger.error(exp.getMessage(), exp);
		}
		return cipeprojectList;
	}

	/**
	 * @return
	 */
	public Map<Integer, String> getThemeList() {
		Map<Integer, String> themes = new HashMap<Integer, String>();
		/*
		 * themes.put(1, "abc"); themes.put(2, "cde");
		 */// TODO Auto-generated method stub
		return themes;
	}

	@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = { CipeprojectException.class })
	public Cipeproject saveOrUpdatePartnerGrantCipeProject(Cipeproject cipeproject, Integer userId, boolean validateUniqueProject) throws CipeprojectException {
		Cipeproject savedCipeproject = saveCipeproject(cipeproject, userId, validateUniqueProject);

		if (cipeproject.getId() == null || cipeproject.getId() == 0) {
			Audits audit = new Audits();

			User user = userService.findById(userId);

			audit.setCipeproject(savedCipeproject);
			audit.setCreatedBy(user);
			audit.setUpdatedBy(user);
			audit.setCreationDate(DateUtil.getCurrentDate());
			audit.setUpdationDate(DateUtil.getCurrentDate());

			auditsService.persist(audit);
		} /*
		 * else { // TODO: probably update setUpdatedBy() & setUpdationDate()
		 * methods }
		 */
		// System.out.println("projecttype  " +
		// cipeproject.getCipeprojecttype().getId());
		return savedCipeproject;
	}

	public Cipeproject saveCipeproject(Cipeproject cipeproject, Integer userId, boolean validateUniqueProject) throws CipeprojectException {
		if (cipeproject != null) {
			User user = userService.findById(userId);
			Cipeproject dbCipeproject = findById(cipeproject.getId());
			if (dbCipeproject == null) {
				dbCipeproject = new Cipeproject();
				dbCipeproject.setCreatedBy(user);
				dbCipeproject.setCreationDate(DateUtil.getCurrentDate());
			} else {
				saveModification(dbCipeproject, cipeproject, user);
			}

			if (validateUniqueProject && cipeproject.getProjectID() != null && cipeproject.getId() == null) {
				Long total = this.countByProjectID(cipeproject.getProjectID());
				if (total > 0) {
					throw new CipeprojectException(CipeprojectException.DUPLICATE_PROJECT_ID_FOUND, "Duplicate Project ID found. Please enter unique Project ID.");
				}
			}
			if (null != cipeproject.getProjectID()) {
				dbCipeproject.setProjectID(cipeproject.getProjectID());
			}
			if (cipeproject.getMasterProject() != null && cipeproject.getMasterProject().getId() != null && cipeproject.getMasterProject().getId() > 0) {
				dbCipeproject.setMasterProject(cipeproject.getMasterProject());
			} else {
				dbCipeproject.setMasterProject(null);
			}
			dbCipeproject.setMatchingFunds(cipeproject.getMatchingFunds());
			dbCipeproject.setPartnerGrantMatchAmount(cipeproject.getPartnerGrantMatchAmount());
			dbCipeproject.setPartnerGrantFunds(cipeproject.getPartnerGrantFunds());
			dbCipeproject.setPartnerGrantStartDate(cipeproject.getPartnerGrantStartDate());
			dbCipeproject.setPartnerGrantEndDate(cipeproject.getPartnerGrantEndDate());
			dbCipeproject.setAcronym(cipeproject.getAcronym());
			dbCipeproject.setProjectimpact(cipeproject.getProjectimpact());

			if (cipeproject.getPartner() != null && cipeproject.getPartner().getId() != null && cipeproject.getPartner().getId() > 0) {
				dbCipeproject.setPartner(cipeproject.getPartner());
			} else {
				dbCipeproject.setPartner(null);
			}

			if (cipeproject.getParentProject() != null && cipeproject.getParentProject().getId() != null && cipeproject.getParentProject().getId() > 0
					&& cipeproject.getFormName() == null) {
				dbCipeproject.setParentProject(cipeproject.getParentProject());
			}
			// else {
			// dbCipeproject.setParentProject(null);
			// }

			dbCipeproject.setProjectTitle(cipeproject.getProjectTitle());
			if (cipeproject.getFormName() == null) {
				dbCipeproject.setApprovedFileLocation(cipeproject.getApprovedFileLocation());
				dbCipeproject.setNedIdentifier(cipeproject.getNedIdentifier());
				dbCipeproject.setFileLocation(cipeproject.getFileLocation());
				dbCipeproject.setCostCenterNumber(cipeproject.getCostCenterNumber());
				dbCipeproject.setAlphaidentifier(cipeproject.getAlphaidentifier());
			}

			if (cipeproject.getDonoraward() != null && cipeproject.getDonoraward().getId() != null && cipeproject.getDonoraward().getId() > 0) {
				dbCipeproject.setDonoraward(cipeproject.getDonoraward());
			} else {
				dbCipeproject.setDonoraward(null);
			}

			dbCipeproject.setProjectStartDate(cipeproject.getProjectStartDate());
			dbCipeproject.setProjectEndDate(cipeproject.getProjectEndDate());
			Cipeprojecttype cipeprojecttype = cipeproject.getCipeprojecttype();
			if (null != cipeprojecttype) {
				dbCipeproject.setCipeprojecttype(cipeprojecttype);
			} else {
				Cipeprojecttype type = this.cipeprojecttypeService.findByDisplayName(Constants.PartnerGrant);
				dbCipeproject.setCipeprojecttype(type);
			}
			Cipeprojectstatus cipeprojectstatus = cipeproject.getCipeprojectstatus();
			if (null != cipeproject) {
				dbCipeproject.setCipeprojectstatus(cipeprojectstatus);
			}
			Region region = cipeproject.getRegion();
			if (null != region) {
				dbCipeproject.setRegion(region);
			}
			Country country = cipeproject.getCountry();
			if (null != country) {
				dbCipeproject.setCountry(country);
			}
			User seniorProgramOfficer = cipeproject.getSeniorProgramOfficer();
			if (null != seniorProgramOfficer) {
				dbCipeproject.setSeniorProgramOfficer(seniorProgramOfficer);
			}
			User programOfficer = cipeproject.getProgramOfficer();
			if (null != programOfficer) {
				dbCipeproject.setProgramOfficer(programOfficer);
			}
			User programAssistant = cipeproject.getProgramAssistant();
			if (null != programAssistant && programAssistant.getId() != null && programAssistant.getId() > 0) {
				dbCipeproject.setProgramAssistant(programAssistant);
			} else {
				dbCipeproject.setProgramAssistant(null);
			}
			Organizationtype organzatOrganizationtype = cipeproject.getOrganizationtype();
			if (null != organzatOrganizationtype) {
				dbCipeproject.setOrganizationtype(organzatOrganizationtype);
			}
			dbCipeproject.setUpdatedBy(user);
			dbCipeproject.setManagementFunds(cipeproject.getManagementFunds());
			dbCipeproject.setRiskAssessmentScore(cipeproject.getRiskAssessmentScore());
			dbCipeproject.setMemo(cipeproject.getMemo());
			dbCipeproject.setAccountingQuestionnaireReceived(cipeproject.getAccountingQuestionnaireReceived());
			dbCipeproject.setTerroristCheckPerformed(cipeproject.getTerroristCheckPerformed());
			dbCipeproject.setBlockTimeSheet(cipeproject.getBlockTimeSheet());
			dbCipeproject.setOverride(cipeproject.getOverride());
			dbCipeproject.setStatusoverride(cipeproject.getStatusoverride());
			// theme info
			dbCipeproject.setThemeaccesstoinfo(cipeproject.getThemeaccesstoinfo());
			dbCipeproject.setThemebusassocdev(cipeproject.getThemebusassocdev());
			dbCipeproject.setThemecorporategovernance(cipeproject.getThemecorporategovernance());
			dbCipeproject.setThemecorruption(cipeproject.getThemecorruption());
			dbCipeproject.setThemedemocraticgovernance(cipeproject.getThemedemocraticgovernance());
			dbCipeproject.setThemeinformalsectorproperty(cipeproject.getThemeinformalsectorproperty());
			dbCipeproject.setThemelegalregreform(cipeproject.getThemelegalregreform());
			dbCipeproject.setThemewomenyouth(cipeproject.getThemeinformalsectorproperty());
			// line of work
			dbCipeproject.setLowcipeadvocacy(cipeproject.getLowcipeadvocacy());
			dbCipeproject.setLowpartnership(cipeproject.getLowpartnership());
			dbCipeproject.setLowproorgdevelopment(cipeproject.getLowproorgdevelopment());
			dbCipeproject.setUpdationDate(DateUtil.getCurrentDate());
			if (dbCipeproject.getId() == null || dbCipeproject.getId() == 0) {
				persist(dbCipeproject); // for creating the entity
			} else {
				dbCipeproject = merge(dbCipeproject); // for merging (merge does
														// not feed
				// automatically the pk if it is null)
			}
			return dbCipeproject;
		}
		return null;
	}

	public Cipeproject saveKnowledgeManagement(Cipeproject cipeproject, Integer userId, boolean validateUniqueProject) throws CipeprojectException {
		if (cipeproject != null) {
			User user = userService.findById(userId);
			Cipeproject dbCipeproject = findById(cipeproject.getId());
			if (dbCipeproject == null) {
				dbCipeproject = new Cipeproject();
				dbCipeproject.setCreatedBy(user);
				dbCipeproject.setCreationDate(DateUtil.getCurrentDate());
			} else {
				// saveModification(dbCipeproject, cipeproject, user);
			}
			dbCipeproject.setProjectimpact(cipeproject.getProjectimpact());
			Organizationtype organzatOrganizationtype = cipeproject.getOrganizationtype();
			if (null != organzatOrganizationtype && null != organzatOrganizationtype.getId()) {
				dbCipeproject.setOrganizationtype(organzatOrganizationtype);
			} else {
				dbCipeproject.setOrganizationtype(null);
			}
			// theme info
			dbCipeproject.setThemeaccesstoinfo(cipeproject.getThemeaccesstoinfo());
			dbCipeproject.setThemebusassocdev(cipeproject.getThemebusassocdev());
			dbCipeproject.setThemecorporategovernance(cipeproject.getThemecorporategovernance());
			dbCipeproject.setThemecorruption(cipeproject.getThemecorruption());
			dbCipeproject.setThemedemocraticgovernance(cipeproject.getThemedemocraticgovernance());
			dbCipeproject.setThemeinformalsectorproperty(cipeproject.getThemeinformalsectorproperty());
			dbCipeproject.setThemelegalregreform(cipeproject.getThemelegalregreform());
			dbCipeproject.setThemewomenyouth(cipeproject.getThemeinformalsectorproperty());
			// line of work
			dbCipeproject.setLowcipeadvocacy(cipeproject.getLowcipeadvocacy());
			dbCipeproject.setLowpartnership(cipeproject.getLowpartnership());
			dbCipeproject.setLowproorgdevelopment(cipeproject.getLowproorgdevelopment());
			// Set project keywords
			if (null != cipeproject.getSelectedKeywords()) {
				// List<Keyword> projectkeywords = dbCipeproject.getKeywords();
				List<Keyword> projectkeywords = new ArrayList<Keyword>();
				Set<Keyword> keywordSet = new HashSet<Keyword>(projectkeywords);
				for (String keyword : cipeproject.getSelectedKeywords()) {
					Keyword obj = this.keywordService.findById(Integer.valueOf(keyword));
					keywordSet.add(obj);
				}
				List<Keyword> keywordList = new ArrayList<Keyword>(keywordSet);
				dbCipeproject.setKeywords(keywordList);
			}
			dbCipeproject.setUpdatedBy(user);
			dbCipeproject.setUpdationDate(DateUtil.getCurrentDate());
			if (dbCipeproject.getId() == null || dbCipeproject.getId() == 0) {
				persist(dbCipeproject); // for creating the entity
			} else {
				merge(dbCipeproject); // for merging (merge does not feed
				// automatically the pk if it is null)
			}
			return dbCipeproject;
		}
		return null;
	}

	private void saveModification(Cipeproject dbObject, Cipeproject bean, User user) {
		List<Cipeprojectmodification> list = new ArrayList<Cipeprojectmodification>();
		if (!DateUtil2.INSTANCE.isSameDay(dbObject.getProjectStartDate(), bean.getProjectStartDate())) {
			Cipeprojectmodification modification = createModication(dbObject, bean, user);
			Modificationtype type = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.changed.startDate"));
			modification.setModificationType(type);
			modification.setModifiedFrom(DateUtil2.INSTANCE.formatDate(dbObject.getProjectStartDate()));
			modification.setModifiedTo(DateUtil2.INSTANCE.formatDate(bean.getProjectStartDate()));
			list.add(modification);
		}

		if (!DateUtil2.INSTANCE.isSameDay(dbObject.getProjectEndDate(), bean.getProjectEndDate())) {
			Cipeprojectmodification modification = createModication(dbObject, bean, user);
			Modificationtype modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.changed.endDate"));
			modification.setModificationType(modificationType);
			modification.setModifiedFrom(DateUtil2.INSTANCE.formatDate(dbObject.getProjectEndDate()));
			modification.setModifiedTo(DateUtil2.INSTANCE.formatDate(bean.getProjectEndDate()));
			list.add(modification);
			if (dbObject.getAudits() != null ? dbObject.getAudits().getFarequired() : false) {
				Calendar cal = Calendar.getInstance();
				cal.setTime(bean.getProjectEndDate());
				cal.add(Calendar.DATE, -30);
				dbObject.getAudits().setFaselectionmemodue(cal.getTime());
			}

			if (dbObject.getAudits() != null ? dbObject.getAudits().getIarequired() : false) {
				Calendar cal = Calendar.getInstance();
				cal.setTime(bean.getProjectStartDate());
				cal.add(Calendar.MONTH, 8);
				dbObject.getAudits().setIaselectionmemodue(cal.getTime());
			}
		}

		if (!NumberUtil.INSTANCE.isEqual(dbObject.getManagementFunds(), bean.getManagementFunds())) {
			Cipeprojectmodification modification = createModication(dbObject, bean, user);
			Modificationtype modificationType = null;
			if (dbObject.getManagementFunds().compareTo(bean.getManagementFunds()) < 0) {
				modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.changed.managementFunds.increased"));
			} else {
				modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.changed.managementFunds.reduced"));
			}
			modification.setModificationType(modificationType);
			modification.setModifiedFrom(dbObject.getManagementFunds().toPlainString());
			modification.setModifiedTo(bean.getManagementFunds().toPlainString());
			list.add(modification);
		}

		if (dbObject.getCipeprojectstatus() == null && bean.getCipeprojectstatus().getId() > 0
				|| !dbObject.getCipeprojectstatus().getId().equals(bean.getCipeprojectstatus().getId())) {
			Cipeprojectmodification modification = createModication(dbObject, bean, user);
			Modificationtype modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.changed.status"));
			modification.setModificationType(modificationType);
			modification.setModifiedFrom(dbObject.getCipeprojectstatus().getDisplayName());
			Cipeprojectstatus newStatus = cipeprojectstatusService.findById(bean.getCipeprojectstatus().getId());
			modification.setModifiedTo(newStatus.getDisplayName());
			list.add(modification);
		}

		if (!list.isEmpty()) {
			List<Cipeprojectmodification> modifications = dbObject.getCipeprojectmodifications();
			if (modifications == null) {
				dbObject.setCipeprojectmodifications(list);
			} else {
				modifications.addAll(list);
			}
		}
	}

	private Cipeprojectmodification createModication(Cipeproject dbObject, Cipeproject bean, User user) {
		Cipeprojectmodification modification = new Cipeprojectmodification();
		Date currentDate = new Date();
		modification.setCreatedBy(user);
		modification.setCreationDate(currentDate);
		modification.setModifiedBy(user);
		modification.setModifiedDate(currentDate);
		modification.setCipeproject(dbObject);
		modification.setAttachment(bean.getModificationDocumentLocation());
		return modification;
	}

	@Transactional(readOnly = true)
	public Cipeproject getCipeProject(Integer projectId, List<String> columns) throws QueryException {
		StringBuilder query = new StringBuilder("SELECT ");
		if (columns != null && columns.size() > 0) {
			int i = 0;
			for (; i < columns.size() - 1; i++) {
				query.append("obj." + columns.get(i) + ", ");
			}
			query.append("obj." + columns.get(i));
		} else {
			query.append("obj");
		}
		query.append(" FROM ");
		query.append(Cipeproject.class.getName());
		query.append(" obj ");
		query.append(" WHERE obj.id = ?1");
		List<Cipeproject> list = dao.getResultList(query.toString(), Cipeproject.class, columns.toArray(new String[0]), new Object[] { projectId });
		return list != null && list.size() > 0 ? list.get(0) : null;
	}

}
